package pnu.ssm.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import pnu.ssm.appinfo.AppInfo;
import pnu.ssm.appinfo.AppListHelper;
import pnu.ssm.key.Key;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

public class HttpConnector {
	
	public static final String TAG = "HttpConnector";
	private static final boolean Debug = true;
	
	//Singleton Design Pattern
	private static HttpConnector connector = new HttpConnector();
	private HttpConnector () { initConnector(); };
	public static HttpConnector getInstance(){ return connector; }
	
	private final String FORBIDDEN_FALSE = "0";
	private final String FORBIDDEN_TRUE = "1";
	
	private final String serverUrl = "http://210.118.69.132/WebLocker/";
//	private final String serverUrl = "http://192.168.0.11:80/DBSeokbong/";
	
	private HttpClient client;
	
	private void initConnector(){
		client = new DefaultHttpClient();
	}
	
	/*
	 * activity methods.
	 * */
	
	//Child Methods!!
	
	public String sendParentPhone(String number, String name){
		if(Debug) Log.d(TAG, "sendParentPhone()");
		JSONObject jsonObj = new JSONObject(); 
		try {
			jsonObj.put("phone_num", number);
			String child_name = URLEncoder.encode(name, "utf-8");
			jsonObj.put("child_name", child_name);
			jsonObj.put("child_type", "PHONE");
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		} catch (UnsupportedEncodingException e) {
			Log.e(TAG, e.getMessage());
		}
		String child_num = jsonPost("Gcm/child_pairing_receiver.php", jsonObj.toString());
		if(child_num.equals("fail")){
			return null;
		}else{
			return child_num;
		}
	}
	
	public String sendAppList(String child_num, Context context){
		if(Debug) Log.d(TAG, "sendAppList()");
		
		JSONObject topContainer = new JSONObject(); // child_num, array object [2개]
		
		try {
			topContainer.put("child_num", child_num);
			JSONArray arrTopContainer = new JSONArray(); // contains appInfo's JSON object (200~300) 
			
			AppListHelper appHelper = AppListHelper.getInstance();
			List<AppInfo> infos = appHelper.getPackages(context);
			if(Debug) Log.d(TAG, ""+infos.size());
			
			for(AppInfo info : infos){
				//Encode AppName to UTF-8 before sending AppName
				String app_name = info.getAppName();
				String encode_app_name = URLEncoder.encode(app_name,"utf-8");
				String package_name = info.getPackageName();
				
				JSONObject token = new JSONObject();
				token.put("app_name", encode_app_name);
				token.put("package_name", package_name);
				
				arrTopContainer.put(token);
			}
			topContainer.put("app_info", arrTopContainer);
			
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		String jsonResult = topContainer.toString();
		String result = jsonPost("Gcm/child_applist_receiver.php", jsonResult);
		
		return result;
	}
	
	public void getChineseSetting(String child_num, SharedPreferences.Editor editor){
		if(Debug) Log.d(TAG,"getChineseSetting() child number : " +child_num);
		String result = null;
		result = jsonGet("Gcm/child_chinese_info_sender.php", 
				new String[]{"child_num"}, 
				new String[]{ child_num });
		
		try {
			
			JSONObject jsonObj = new JSONObject(result);
			String extra_time = (String) jsonObj.get("extra_time");
			String limit_time = (String) jsonObj.get("limit_time");
			String rating = (String) jsonObj.get("rating");
			String obtain_time = (String) jsonObj.get("obtain_time");
			String spare_time = (String) jsonObj.get("spare_time");
			
			editor.putString(Key.extra_time,extra_time);
			editor.putString(Key.limit_time, limit_time);
			editor.putString(Key.rating,rating);
			editor.putString(Key.obtain_time, obtain_time);
			editor.putString(Key.spare_time, spare_time);
			editor.commit();
			
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		} catch (Exception e){
			Log.e(TAG, e.getMessage());
		}
		
	}
	
	public List<AppInfo> getForbiddenAppList(String child_num){
		if(Debug) Log.d(TAG,"getForbiddenAppList() child number : " +child_num);
		String result = null;
		result = jsonGet("Gcm/child_forbidden_applist_sender.php", 
				new String[]{"child_num","child_type"}, 
				new String[]{ child_num ,"PHONE"});
		List<AppInfo> appList = new ArrayList<AppInfo>();
		try {
			JSONArray jsonArray = new JSONArray(result);
			for(int i=0; i<jsonArray.length(); i++){
				JSONObject jsonObj = jsonArray.getJSONObject(i);
				String app_name = (String) jsonObj.get("app_name");
				String package_name = (String) jsonObj.get("package_name");
				String forbiddenStr = (String) jsonObj.get("forbidden");
				boolean forbbiden = false;
				if(forbiddenStr.equals(FORBIDDEN_TRUE)) 
					forbbiden = true;
				else forbbiden = false;
				AppInfo info = new AppInfo(app_name, package_name, forbbiden);
				appList.add(info);
			}
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		} catch (Exception e){
			Log.e(TAG, e.getMessage());
		}
		return appList;
	}
	
	// this method is critical! it sends Registration ID to 3rd party server
	public String sendRegistrationID(String child_num, String regId){
		if(Debug) Log.d(TAG, "send registration id ["+regId+"] to server");
		JSONObject jsonObj = new JSONObject();
		try {
			jsonObj.put("child_num", child_num);
			jsonObj.put("registrationId", regId);
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		}
		String result = jsonPost("Gcm/child_id_receiver.php", jsonObj.toString());
		return result;
	}
	
	public String sendChineseState(String child_num, String obtain_time){
		JSONObject jsonObj = new JSONObject();
		try {
			jsonObj.put("child_num", child_num);
			jsonObj.put("obtain_time", obtain_time);
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		}
		String result = jsonPost("Gcm/child_obtain_time_receiver.php",jsonObj.toString());
		return result;
	}
	
	// test methods that need to be modified.
	public String sendMessageTest(String msg){
		if(Debug) Log.d(TAG, "sendMessageTest()");
		
		JSONObject jsonObj = new JSONObject();
		try {
			jsonObj.put("message", msg);
		} catch (JSONException e) {
			Log.e(TAG, e.getMessage());
		}
		String result = jsonPost("Gcm/gcm_messenger.php", jsonObj.toString());
		return result;
	}
	
	
	
	
	/*
	 * common get, post methods
	 */
	
	public String jsonGet(String url,String[] keys, String[] values){
		String targetUrl = serverUrl;
		url += "/?";
		
		targetUrl += url+keys[0]+"="+values[0];
		for(int i=1; i<values.length; i++){
			targetUrl += "&"+keys[i]+"="+values[i];
		}
		
		// Http communication using get method
		HttpGet httpGet = new HttpGet(targetUrl);
		String content = "";
		String line = "";
		
		try {
			HttpResponse response = client.execute(httpGet);
			HttpEntity entity = response.getEntity();
			Log.d(TAG, response.getStatusLine().toString());
			
			BufferedReader in = new BufferedReader(
					new InputStreamReader(entity.getContent()));
			while((line = in.readLine())!=null){
				content+=line;
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//decoding
		String decodeContentStr = decodeURLtoUTF8(content);
		Log.d(TAG, "[get] received : " + decodeContentStr);
		return decodeContentStr;
	}
	
	public String jsonPost(String url, String jsonParam) {
		Log.d(TAG, "Json Post call()");
		String targetUrl = serverUrl + url;

		// Http communication using post method.
		String content = "";
		String line = "";

		try {
			HttpResponse response = makePostRequest(targetUrl, jsonParam);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				BufferedReader in = new BufferedReader(new InputStreamReader(
						response.getEntity().getContent()));
				while ((line = in.readLine()) != null) {
					content += line;
				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//Decoding...
		String decodeContentStr = decodeURLtoUTF8(content);
		Log.d(TAG, "[post] received : " + decodeContentStr);
		return decodeContentStr;
	}
	
	/*
	 * Common methods to requests
	 * */

	public static HttpResponse makeGetRequest(String uri, String json) {
		try {
			if(Debug) Log.d(TAG, "makeGetRequest()");
			HttpGet httpGet = new HttpGet(uri);
			httpGet.setHeader("Accept", "application/json;");
			httpGet.setHeader("Content-type", "application/json;");
			return new DefaultHttpClient().execute(httpGet);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}


	public static HttpResponse makePostRequest(String uri, String json) {
	    try {
	    	if(Debug) Log.d(TAG, "makePostRequest()");
	    	String encodeJson = URLEncoder.encode(json, "utf-8");
	        HttpPost httpPost = new HttpPost(uri);
	        httpPost.setEntity(new StringEntity(encodeJson));
	        httpPost.setHeader("Accept", "application/json");
	        httpPost.setHeader("Content-type", "application/json");
	        return new DefaultHttpClient().execute(httpPost);
	    } catch (UnsupportedEncodingException e) {
	        e.printStackTrace();
	    } catch (ClientProtocolException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	    return null;
	}
	
	private static String decodeURLtoUTF8(String content){
		String decodeContentStr = null;
		try {
		decodeContentStr = URLDecoder.decode(content, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return decodeContentStr;
	}
}
